// Author: wsfuyibing <682805@qq.com>
// Date: 2025-05-19

package amap

import (
	"context"
	"encoding/json"
	"fmt"
	"gitee.com/go-libs/log"
	"github.com/valyala/fasthttp"
	"net/http"
	"net/url"
	"server/app/config"
	"server/app/kind"
	"server/app/lib/maps/i"
	"strings"
)

type (
	manager struct {
		host string
		key  string
	}

	result struct {
		Status  any    `json:"status"`
		Message string `json:"info"`
	}

	resultForReg struct {
		Data struct {
			Address   string `json:"formatted_address"` // 完整地址
			Component struct {
				Code     string `json:"adcode"`   // 地区编码(如: 340202 表示镜湖区)
				Country  string `json:"country"`  // 国家(如: 中国)
				Province string `json:"province"` // 省份(如: 安徽省)
				City     string `json:"city"`     // 市名(如: 芜湖市)
				CityCode string `json:"citycode"` // 城市区号(如: 0553)
				District string `json:"district"` // 区名(如: 镜湖区)
				Street   string `json:"township"` // 区名(如: 弋矶山街道)
			} `json:"addressComponent"`
		} `json:"regeocode"`
	}
)

func New() i.Manager {
	return (&manager{}).init()
}

// GetAddressByLocation
// 坐标系反查.
// @link https://lbs.amap.com/api/webservice/guide/api/georegeo
func (o *manager) GetAddressByLocation(ctx context.Context, latitude, longitude kind.GeoPoint) (loc i.Location, err error) {
	var ptr = &resultForReg{}

	// 1. 请求数据.
	if err = o.send(ctx, ptr, "GET", "/v3/geocode/regeo", map[string]any{
		"key":       o.key,
		"location":  fmt.Sprintf(`%f,%f`, longitude, latitude),
		"output":    "json",
		"radius":    300,
		"extension": "base",
	}); err != nil {
		return
	}

	// 2. 数据转换.
	loc.Code = ptr.Data.Component.Code
	loc.Country = ptr.Data.Component.Country
	loc.Province = ptr.Data.Component.Province
	loc.City = ptr.Data.Component.City
	loc.CityCode = ptr.Data.Component.CityCode
	loc.District = ptr.Data.Component.District
	loc.Street = ptr.Data.Component.Street

	// 3. 详细地址.
	loc.Address = ptr.Data.Address
	loc.Name = loc.Address

	for _, s := range []string{
		loc.Province,
		loc.City,
		loc.District,
		loc.Street,
	} {
		loc.Name = strings.TrimPrefix(loc.Name, s)
	}
	return
}

// +---------------------------------------------------------------------------+
// | Access methods                                                            |
// +---------------------------------------------------------------------------+

func (o *manager) init() *manager {
	o.host = config.Maps.GetAmapHost()
	o.key = config.Maps.GetAmapKey()
	return o
}

func (o *manager) send(ctx context.Context, ptr any, mtd, path string, query map[string]any) (err error) {
	var (
		body []byte
		req  = fasthttp.AcquireRequest()
		res  = fasthttp.AcquireResponse()
		src  = fmt.Sprintf(`%s%s`, o.host, path)
	)

	// 1. 监听结束.
	defer func() {
		// 1.1 捕获异常.
		if r := recover(); r != nil {
			log.Fatalfc(ctx, `[amap] panic: fatal="%v"`, r)

			if err == nil {
				err = fmt.Errorf(`%v`, r)
			}
		}

		// 1.2 释放资源.
		fasthttp.ReleaseRequest(req)
		fasthttp.ReleaseResponse(res)

		// 1.3 记录结果.
		if err != nil {
			log.Warnfc(ctx, `[amqp] request end: error="%v"`, err)
		} else {
			log.Infofc(ctx, `[amqp] request end`)
		}
	}()

	// 2. 请求参数.
	req.Header.SetMethod(mtd)
	req.Header.SetContentType(config.Maps.GetAmapContentType())

	// 3. 构建地址.
	q := url.Values{}
	for k, v := range query {
		q.Add(k, fmt.Sprintf(`%v`, v))
	}

	// 3.1 追加参数.
	req.Header.SetRequestURI(src + "?" + q.Encode())
	log.Infofc(ctx, `[amqp] begin request: url="%s"`, src)

	// 4. 请求数据.

	// 5. 请求过程.
	if err = fasthttp.DoTimeout(req, res, config.Maps.GetAmapTimeoutDuration()); err != nil {
		return
	} else {
		body = res.Body()
		log.Debugfc(ctx, `[amqp] request result: %s`, body)
	}

	// 5.1 状态错误.
	if code := res.StatusCode(); code != http.StatusOK {
		err = fmt.Errorf(`HTTP/1.1 %d %s`, code, http.StatusText(code))
		return
	}

	// 6. 请求结果.
	ret := &result{}
	if err = json.Unmarshal(body, ret); err == nil {
		if code := fmt.Sprintf(`%v`, ret.Status); code != "1" {
			err = fmt.Errorf(`%s`, ret.Message)
			return
		}
	}

	// 6.1 转码处理.
	err = json.Unmarshal(body, ptr)
	return
}
